#include "Scott.h"

#if !defined(WIN32)
#  include <dlfcn.h>  
#endif

StringVectorSp Scott::GetInstalledPluginNames() 
{
	StringVectorSp v(new StringVector);

	// Find all the dynamic libraries in the directory Plugins
	
	path pluginDir( PLUGIN_DIR );

	// If the Plugin directory is not present will be created
	if ( !exists( pluginDir) )
	{
		create_directory(pluginDir);
	}

	try
	{
		directory_iterator itr(pluginDir), end_itr;

		for( ; itr != end_itr; ++itr )
		{			
			if ( is_regular_file( itr->status() ) )
			{
				string extension = ".dll";
				
				#if !defined(WIN32)
					extension = ".so";	
				#endif

				path fileName = itr->leaf();

				if ( fileName.extension() == extension )
				{
					fileName.replace_extension("");
					v->push_back( fileName.external_file_string() );									
				}
			}
		}
	}
	catch(std::exception ex)
	{
	}

	return v;
}

PluginSp Scott::CreatePlugin(string pluginName, PluginSpMapSp plugins, INameResolutorSp nameResolutor)
{
	// Create the plugin file name
	string pluginFileName = PLUGIN_DIR + pluginName;	

#if defined(WIN32)
	pluginFileName += ".dll";
#else
	pluginFileName += ".so";
#endif

#if defined(WIN32)

	// Load the plugin library
	HMODULE pluginMod = ::LoadLibraryA( pluginFileName.c_str() );

	if (pluginMod != NULL)
	{
		LoadPluginFunction loadPlugin = (LoadPluginFunction) ::GetProcAddress (pluginMod, "LoadPlugin");

		if (loadPlugin != NULL)
		{
			PluginSp plugin = PluginSp((*loadPlugin)());
			plugin->InitializePlugin(plugins, nameResolutor);

			return plugin;
		}

		::FreeLibrary (pluginMod);
		throw SException("Error: cannot instantiate the plugin " + pluginName);
	}

#else
	
	void *handle = dlopen( pluginFileName.c_str(), RTLD_NOW | RTLD_GLOBAL);

	if (handle != NULL)
	{
		LoadPluginFunction loadPlugin = (LoadPluginFunction) dlsym (handle, "LoadPlugin");

		if (loadPlugin != NULL)
		{
			PluginSp plugin = PluginSp((*loadPlugin)());
			plugin->InitializePlugin(plugins, nameResolutor);

			return plugin;
		}

		dlclose(handle);
	}
	else
	{
		cout << "Error: " << dlerror() << endl;
	}

#endif

	throw SException("Error: the plugin '" + pluginName + "' is not installed.");
}
